#include "keyfinder.h"
#include <QApplication>
#include <QDebug>
#include <QProcess>
#include <QScrollArea>
#include <QShortcut>
#include <QVariant>
#include <qchar.h>
#include <qdebug.h>
#include <qglobal.h>
#include <qgroupbox.h>
#include <qnamespace.h>

int KeyFinderSingleFileListModel::rowCount(const QModelIndex &parent) const {
  Q_UNUSED(parent);
  return items.size();
}

QVariant KeyFinderSingleFileListModel::data(const QModelIndex &index,
                                            int role) const {
  if (!index.isValid() || index.row() >= items.size())
    return QVariant();

  if (role == Qt::UserRole) { // 使用 Qt::UserRole 返回 KeyFinderFileItem 数据
    return QVariant::fromValue(
        items.at(index.row())); // items 是 KeyFinderFileItem 的容器
  }

  if (role == Qt::DisplayRole) {
    // const KeyFinderFileItem &item = items.at(index.row());
    // return QVariant::fromValue(item); // 返回列表项的文本数据
    return "";
  }

  if (role == Qt::SizeHintRole) {
    return rowHeights.value(index.row(), QSize(100, 30));
  }

  return QVariant();
}

bool KeyFinderSingleFileListModel::setData(const QModelIndex &index,
                                           const QVariant &value, int role) {
  if (!index.isValid())
    return false;

  if (role == Qt::SizeHintRole) {
    QSize newSize = value.toSize();
    rowHeights[index.row()] = newSize;
    emit dataChanged(index, index, {Qt::SizeHintRole}); // 触发更新
    return true;
  }

  return QAbstractListModel::setData(index, value, role);
}

void KeyFinderSingleFileListModel::setItems(
    const QList<KeyFinderFileItem> &newItems) {
  beginResetModel();
  items = newItems;
  endResetModel();
}

void KeyFinderSingleFileListModel::clear() {
  beginResetModel();
  items.clear();
  endResetModel();
}

KeyFinderFileItemWidget::KeyFinderFileItemWidget(QWidget *parent)
    : QWidget(parent) {
  groupBox = new QGroupBox("Rg:", this);
  groupBox->setStyleSheet("QGroupBox::title {"
                          "  color: #3a8883;"      // 设置标题颜色
                          "  white-space: normal;" // 允许自动换行
                          "  subcontrol-origin: margin;"
                          "  subcontrol-position: top left;"
                          "  left: 0.25em;"
                          "}");
  groupBoxLayout = new QVBoxLayout();
  QVBoxLayout *layout = new QVBoxLayout(this);
  groupBox->setLayout(groupBoxLayout);
  layout->addWidget(groupBox);
  layout->addStretch(1);
}

KeyFinderLinesWidget::KeyFinderLinesWidget(QWidget *parent) : QWidget(parent) {
  linesWidget = new QListWidget(this);
  QVBoxLayout *layout = new QVBoxLayout(this);
  layout->addWidget(linesWidget);
  setLayout(layout);
}

KeyFinderLineItemWidget::KeyFinderLineItemWidget(KeyFinderLineItem *line,
                                                 QWidget *parent)
    : QWidget(parent) {
  QHBoxLayout *layout = new QHBoxLayout(this);
  layout->setContentsMargins(0, 0, 0, 0);

  QString lineNumber = QString::number(line->lineNumber);
  QString lineContent = line->lineContent;
  QString matchedContent = line->matchedContent;

  QLabel *lineNumberLabel = new QLabel(lineNumber + ":", this);
  lineNumberLabel->setStyleSheet("color: #14b918;");
  layout->addWidget(lineNumberLabel);

  QStringList lineContentSplit =
      lineContent.split(matchedContent, Qt::KeepEmptyParts);
  QString lineContentDone;
  for (int i = 0; i < lineContentSplit.size(); i++) {
    lineContentDone += lineContentSplit[i].toHtmlEscaped();
    if (i != lineContentSplit.size() - 1) {
      lineContentDone += "<span style='color: #c0392b'>" +
                         matchedContent.toHtmlEscaped() + "</span>";
    }
  }

  QLabel *lineContentLabel =
      new QLabel("<span>" + lineContentDone + "</span>", this);
  lineContentLabel->setWordWrap(true);
  lineContentLabel->setSizePolicy(QSizePolicy::Expanding,
                                  QSizePolicy::Preferred);

  layout->addWidget(lineContentLabel);
}

void KeyFinderLinesWidget::jumpToLine(int row) {
  KeyFinderLineItem line = p_lines[row];
  if (p_filePath.isEmpty())
    return;
  editor.gotoPosition(p_filePath, line.lineNumber - 1,
   line.lineContent.indexOf(line.matchedContent) + line.matchedContent.length());
}

void KeyFinderLinesWidget::setLines(QList<KeyFinderLineItem> lines,
                                    QString filePath) {
  p_filePath = filePath;
  p_lines = lines;

  for (auto line : lines) {

    QListWidgetItem *item = new QListWidgetItem(linesWidget);
    KeyFinderLineItemWidget *lineWidget = new KeyFinderLineItemWidget(&line);
    // item->setSizeHint(lineWidget->sizeHint());
    linesWidget->setItemWidget(item, lineWidget);
    item->setSizeHint(lineWidget->sizeHint());
  }

  int totalHeight = 0;

  // 遍历所有行计算高度
  for (int i = 0; i < linesWidget->count(); ++i) {
    totalHeight += linesWidget->sizeHintForRow(i);
  }

  // 加上框架的高度
  totalHeight += 2 * linesWidget->frameWidth();
  int maxHeight = 400;
  if (totalHeight > maxHeight)
    totalHeight = maxHeight;
  linesWidget->setFixedHeight(totalHeight);

  connect(linesWidget, &QListWidget::itemDoubleClicked, this,
          [this](QListWidgetItem *item) {
            int row = linesWidget->row(item);
            jumpToLine(row);
          });
}

void KeyFinderFileItemWidget::setItem(KeyFinderFileItem item) {
  groupBox->setTitle("Rg: " + item.filePath);
  linesWidget = new KeyFinderLinesWidget();
  linesWidget->setLines(item.lines, item.filePath);
  groupBoxLayout->addWidget(linesWidget);
}

void KeyFinderFileItemWidget::jumpToSelectedItem() {
  int row = getRow();
  if (row < 0)
    return;
  linesWidget->jumpToLine(row);
}

int KeyFinderFileItemWidget::getRow() {
  return linesWidget->linesWidget->currentRow();
}

int KeyFinderFileItemWidget::countRow() {
  return linesWidget->linesWidget->count();
}

void KeyFinderFileItemWidget::setIndex(int row) {
  linesWidget->linesWidget->setCurrentRow(row);
}

bool KeyFinderFileItemWidget::isSelectedLast() {
  return getRow() == countRow() - 1;
}

bool KeyFinderFileItemWidget::isSelectedFirst() { return getRow() == 0; }

void KeyFinderFileItemWidget::scrollToRow(int row) {
  setIndex(row);
  // emit scrollFileTo(row);
}

void KeyFinderFileItemWidget::selectedPrev() {
  if (!isSelectedFirst()) {
    int currRow = getRow();
    if (currRow == -1)
      currRow = countRow() - 1;
    else
      currRow--;
    scrollToRow(currRow);
  }
}

void KeyFinderFileItemWidget::selectedNext() {
  if (!isSelectedLast()) {
    scrollToRow(getRow() + 1);
  }
}

void KeyFinderFileItemWidget::unSelected() { scrollToRow(-1); }

QList<KeyFinderFileItem> KeyFinder::runRg(const QString searchTerm,
                                          const QString searchPath,
                                          const bool isRegex) {
  QProcess process;

  QString absoulteSearchPath = searchPath;

  if (absoulteSearchPath.startsWith("."))
    absoulteSearchPath = defalutSearchPath + "/" + absoulteSearchPath;

  if (absoulteSearchPath.startsWith("~"))
    absoulteSearchPath = absoulteSearchPath.replace(0, 1, QDir::homePath());

  absoulteSearchPath = QDir(absoulteSearchPath).absolutePath();

  // 设置要执行的命令和参数，比如在当前目录搜索 "search_term"
  QString program = "rg"; // ripgrep 命令
  QStringList arguments, o_arguments;
  if (!isRegex)
    arguments << "-F";
  arguments << "-S" << "-n" << searchTerm
            << absoulteSearchPath; // 搜索关键词 "search_term" 在当前目录 "."
  o_arguments = arguments;
  o_arguments << "-o";

  // 启动命令并等待完成
  process.start(program, arguments);
  bool finished = process.waitForFinished(100); // 等待进程完成

  // 获取标准输出
  QString output = process.readAllStandardOutput();
  QString errorOutput = process.readAllStandardError(); // 获取错误输出
  QStringList lines = output.split('\n', Qt::KeepEmptyParts);

  if (!finished) {
    process.kill();
    process.waitForFinished();
    
    // 移除最后一行，防止错误输出
    if (!lines.isEmpty())
        lines.removeLast();
  }

  if (lines.size() > 300) {
        lines = lines.mid(0, 300); // 截取前 300 行
  }
  // 重新拼接为字符串
  output = lines.join('\n');

  if (output.isEmpty()) {
    if (errorOutput.isEmpty()) {
      errorOutput = "Can't search anything use the KeyWord: " + searchTerm;
    }
    QList<KeyFinderFileItem> errs;
    KeyFinderFileItem err;
    KeyFinderLineItem errl;
    err.error = errorOutput;
    errl.lineContent = errorOutput;
    errl.lineNumber = -1;
    errl.matchedContent = errorOutput;
    err.lines.append(errl);
    errs.append(err);
    return errs;
  } else {
    process.start(program, o_arguments);
    bool finished = process.waitForFinished(100);
    QString oOutput = process.readAllStandardOutput();
    if (!finished) {
      process.kill();
      process.waitForFinished();
    }
    return parseRgOutput(output, oOutput);
  }
}

QList<KeyFinderFileItem> KeyFinder::parseRgOutput(const QString rgOutput,
                                                  const QString oOutput) {
  QRegularExpression regex(R"((.*):(\d+):(.*))");

  // 逐行解析输出
  QRegularExpressionMatchIterator i = regex.globalMatch(rgOutput);
  QRegularExpressionMatchIterator oi = regex.globalMatch(oOutput);

  QList<KeyFinderFileItem> fileResults;
  QMap<QString, QMap<int, QString>> matchedContentMap;

  while (oi.hasNext()) {
    QRegularExpressionMatch omatch = oi.next();
    QString filePath = omatch.captured(1);
    int lineNumber = omatch.captured(2).toInt();
    QString matchedContent = omatch.captured(3);
    matchedContentMap[filePath][lineNumber] = matchedContent;
  }

  while (i.hasNext()) {
    QRegularExpressionMatch match = i.next();
    QString filePath = match.captured(1);
    int lineNumber = match.captured(2).toInt();
    QString lineContent = match.captured(3);

    KeyFinderLineItem lineResult;
    lineResult.lineNumber = lineNumber;
    lineResult.lineContent = lineContent;
    lineResult.matchedContent = matchedContentMap[filePath][lineNumber];

    if (fileResults.isEmpty() || fileResults.last().filePath != filePath) {
      KeyFinderFileItem fileResult;
      fileResult.filePath = filePath;
      fileResult.lines.append(lineResult);
      fileResults.append(fileResult);
    } else {
      fileResults.last().lines.append(lineResult);
    }
  }

  return fileResults;
}

void KeyFinderLineEdit::keyPressEvent(QKeyEvent *event) {
  if (event->key() == Qt::Key_Up) {
    emit selectPrevSignal();
  } else if (event->key() == Qt::Key_Down) {
    emit selectNextSignal();
  } else if (event->key() == Qt::Key_Return) {
    emit jumpToSelectedSignal();
  } else {
    QLineEdit::keyPressEvent(event); // 保留原有功能
  }
}

// KeyFinder 构造函数
KeyFinder::KeyFinder(QWidget *parent) : QWidget(parent) {
  mainLayout = new QVBoxLayout(this);

  setWindowFlags(Qt::FramelessWindowHint);
  QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
  connect(shortcut, &QShortcut::activated, this, &KeyFinder::close);

  // 创建输入框
  searchArgInput = new KeyFinderLineEdit(this);
  // searchArgInput->setPlaceholderText("#");
  searchArgInput->setText("#");
  mainLayout->addWidget(searchArgInput);

  resultFilesView = new QListView(this);
  resultFilesModel = new KeyFinderSingleFileListModel();
  resultFilesView->setUniformItemSizes(false);
  resultFilesView->setModel(resultFilesModel);
  resultFilesSelectionModel = resultFilesView->selectionModel();
  mainLayout->addWidget(resultFilesView);

  connect(searchArgInput, &QLineEdit::textChanged, this,
          &KeyFinder::performSearch);

  connect(searchArgInput, &KeyFinderLineEdit::selectPrevSignal, this,
          &KeyFinder::selectPrevItem);
  connect(searchArgInput, &KeyFinderLineEdit::selectNextSignal, this,
          &KeyFinder::selectNextItem);
  connect(searchArgInput, &KeyFinderLineEdit::jumpToSelectedSignal, this,
          &KeyFinder::jumpToSelectedItem);
}

void KeyFinder::setItemWidget() {
  fileItemWidgets = new QList<KeyFinderFileItemWidget *>;

  // 设置每一项的自定义组件
  for (int i = 0; i < resultFilesModel->rowCount(); ++i) {
    QModelIndex index = resultFilesModel->index(i, 0);
    QVariant currData = index.data(Qt::UserRole);
    KeyFinderFileItem currItem = currData.value<KeyFinderFileItem>();
    auto *widget = new KeyFinderFileItemWidget();
    widget->setItem(currItem);
    fileItemWidgets->append(widget);
    resultFilesView->setIndexWidget(index, widget);
    resultFilesModel->setData(index, widget->sizeHint(), Qt::SizeHintRole);
    // connect(widget, &KeyFinderFileItemWidget::scrollFileTo, this,
    //         [this, widget](int row) {
    //           if (row < 0)
    //             return;
    //           qInfo() << row;
    //           auto item = widget->linesWidget->linesWidget->item(row);
    //           auto itemWidget =
    //               widget->linesWidget->linesWidget->itemWidget(item);
    //           qInfo() << itemWidget->sizeHint();
    //         });
  }
  resultFilesView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}

void KeyFinder::performSearch() {
  // 清空现有结果
  resultFilesModel->clear();

  QString searchArg = searchArgInput->text();
  QString searchPath = defalutSearchPath;
  QString searchContent = "";
  bool isRegex = true;
  auto searchArgLines = searchArg.split("\n");
  if (searchArgLines.size() > 1) {
    searchArg = searchArgLines.first();
    searchArgInput->setText(searchArg);
  }

  if (searchArg.startsWith("#")) {
    isRegex = true;
  } else if (searchArg.startsWith("$")) {
    isRegex = false;
  } else {
    qWarning() << "Invalid search arg string format!";
    return;
  }

  searchArg = searchArg.mid(1);
  int atIndex = searchArg.lastIndexOf('@');
  if (atIndex != -1) {
    // 有@符号，分离内容和路径
    searchContent = searchArg.left(atIndex);
    QString searchPathTemp = searchArg.mid(atIndex + 1);
    if (!searchPathTemp.isEmpty())
      searchPath = searchPathTemp;
  } else {
    // 没有@符号，只有内容部分
    searchContent = searchArg;
  }

  if (searchContent.isEmpty() || searchContent.length() < 3)
    return;

  QList<KeyFinderFileItem> rgResults =
      runRg(searchContent, searchPath, isRegex);

  resultFilesModel->setItems(rgResults);
  setItemWidget();
  selectNextItem();
}

void KeyFinder::selectPrevItem() {
  if (!resultFilesSelectionModel || resultFilesModel->rowCount() == 0)
    return;

  QModelIndex current = resultFilesSelectionModel->currentIndex();

  int currRow = current.row();
  int rowNum = currRow;

  if (currRow >= 0) {
    KeyFinderFileItemWidget *currFileItemWidget = fileItemWidgets->at(currRow);
    if (currFileItemWidget->isSelectedFirst()) {
      currFileItemWidget->unSelected();
      if (currRow == 0) {
        rowNum = resultFilesModel->rowCount() - 1;
      } else {
        rowNum = currRow - 1;
      }
    } else {
      currFileItemWidget->selectedPrev();
    }
  } else
    rowNum = 0;

  if (rowNum != currRow) {
    QModelIndex prevIndex = resultFilesModel->index(rowNum);
    resultFilesSelectionModel->setCurrentIndex(
        prevIndex, QItemSelectionModel::SelectCurrent);
    fileItemWidgets->at(rowNum)->selectedPrev();
  }
}

void KeyFinder::selectNextItem() {
  if (!resultFilesSelectionModel || resultFilesModel->rowCount() == 0)
    return;

  QModelIndex current = resultFilesSelectionModel->currentIndex();

  int currRow = current.row();
  int rowNum = currRow;

  if (currRow >= 0) {
    KeyFinderFileItemWidget *currFileItemWidget = fileItemWidgets->at(currRow);
    if (currFileItemWidget->isSelectedLast()) {
      currFileItemWidget->unSelected();
      if (currRow >= resultFilesModel->rowCount() - 1) {
        rowNum = 0;
      } else {
        rowNum = currRow + 1;
      }
    } else {
      currFileItemWidget->selectedNext();
    }
  } else
    rowNum = 0;

  if (rowNum != currRow) {
    QModelIndex prevIndex = resultFilesModel->index(rowNum);
    resultFilesSelectionModel->setCurrentIndex(
        prevIndex, QItemSelectionModel::SelectCurrent);
    fileItemWidgets->at(rowNum)->selectedNext();
  }
}

void KeyFinder::jumpToSelectedItem() {
  if (!resultFilesSelectionModel || resultFilesModel->rowCount() == 0)
    return;
  QModelIndex current = resultFilesSelectionModel->currentIndex();
  if (current.row() < 0)
    return;
  KeyFinderFileItemWidget *currFileItemWidget =
      fileItemWidgets->at(current.row());
  currFileItemWidget->jumpToSelectedItem();
}

void KeyFinder::wheelEvent(QWheelEvent *event) {
  // 获取滚轮的角度变化
  int delta = event->angleDelta().y();

  // 判断滚轮方向
  if (delta > 0) {
    // 添加自定义向上滚动的逻辑
    selectPrevItem();
  } else if (delta < 0) {
    // 添加自定义向下滚动的逻辑
    selectNextItem();
  }
}

void KeyFinder::setSearchKey(QString key, bool isRegex) {
  QString stype = "#";
  if (!isRegex)
    stype = "$";
  searchArgInput->setText(stype + key);
}

void KeyFinder::setDefalutSearchPath(QString path) {
  defalutSearchPath = path;
}
